package com.tn.utils;

import cn.hutool.core.lang.Console;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.ArrayList;
import java.util.List;

public class MyBatisLogImpl implements org.apache.ibatis.logging.Log {

	private final Log log;
	private String boundSql;
	public boolean isDebug = false;
	
	public MyBatisLogImpl(String clazz) {
		log = LogFactory.getLog(clazz);
	}
	
	public MyBatisLogImpl() {
		this.log = null;
	}

	public static void main(String[] args) {
//		var s1 = "==>  Preparing: insert into tbl_permission (id, pid, name, type, remark, uri, icon, status, ctime, cuid) select (count(*)+1 + 10000 * ? ) as id, ?, ?, ?, ?, ?, ?, 0, now(), ? from tbl_permission a where type = ?"; 
//		var s2 = "==> Parameters: 3(Integer), 10004(Integer), 测试数据4(String), 3(Integer), 这是测试数据4，可删除(String), /this/isTest4(String), null, 2(Long), 3(Integer)";
		
//		var s1 = " ==>  Preparing: INSERT INTO `oc_users`(`uid`, `displayname`, `password`) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE `password` = ?";
//		var s2 = " ==> Parameters: 1292678444127227904(String), 1292678444127227904(String), 1|$2a$10$mcKHvbh1TTD19nXoOhYcIeHusbXToH8Fjjn4dJ4tLejX5mrsxMjuS(String), 1|$2a$10$mcKHvbh1TTD19nXoOhYcIeHusbXToH8Fjjn4dJ4tLejX5mrsxMjuS(String)";
		
		String s1 = "==>  Preparing: INSERT INTO syslog ( module, type, method, description, req_param, uri, ip, userid, username, ctime, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )";
		String s2 = "==> Parameters: 用户管理-新增(String), 新增(String), xyja.Controller.UserController.add(String), 新增用户功能(String), {password=1231, phone=12232233323, email=a3@a3.com, username=admin3, realname=a3}(String), /usr/add(String), 127.0.0.1(String), 1(Integer), admin(String), 2021-02-02T16:36:12.467773700(LocalDateTime), V1.0(String)";

		MyBatisLogImpl impl = new MyBatisLogImpl();
		impl.isDebug = true;
		
		String[] result = impl.splitSql(s1, s2);
		String q = result[0];
		String p = result[1];
		
		String sql = impl.doSql(s1, s2);
		System.out.println("  sql= " + sql);
	}
	
	public String[] splitSql(String s1, String s2) {
		String flag1 = "==>  Preparing:";
		String flag2 = "==> Parameters:";
		int i1 = s1.indexOf(flag1) + flag1.length();
		int i3 = s2.indexOf(flag2) + flag2.length();

		// 取出未格式化的sql字符串
		String sql = s1.substring(i1);
		// 取出未格式化的参数字符串
		String paramsStr = s2.substring(i3);
		Console.log("取sql: ", sql);
		Console.log("取参数: ", paramsStr);
		
		String[] result = {sql, paramsStr};
		return result;
	}
	public String[] splitSql(String allString) {
		String str = "2020-09-10 16:05:33.220 DEBUG 5001 --- [http-nio-18081-exec-4] xyja.dao.UserInfoMapper.selectList       : ==>  Preparing: SELECT tid,user_id,key_sn,phone,mail,account,status, status_time,utime,ctime FROM user_info WHERE (key_sn = ? AND phone = ? AND mail = ? AND status > ? AND status < ?)\r\n" +
				"2020-09-10 16:05:33.221 DEBUG 5001 --- [http-nio-18081-exec-4] xyja.dao.UserInfoMapper.selectList       : ==> Parameters: 02P6T649059672(String), 15*******28(String), 760466942@qq.com(String), 0(Integer), 99(Integer)\r\n" + 
				"";
		String flag1 = "==>  Preparing:";
		String flag2 = "==> Parameters:";
		int i1 = str.indexOf(flag1) + flag1.length();
		int i2 = str.indexOf("\r\n");
		int i3 = str.indexOf(flag2) + flag2.length();

		// 取出未格式化的sql字符串
		String sql = str.substring(i1, i2);
		// 取出未格式化的参数字符串
		String paramsStr = str.substring(i3);
		Console.log(sql);
		Console.log(paramsStr);
		
		String[] result = {sql, paramsStr};
		return result;
	}
	
	// 去掉无效信息后，填充sql
	public String doSql(String preparing, String parameters) {
		String flag1 = "==>  Preparing:";
		String flag2 = "==> Parameters:";

		// 取出未格式化的sql字符串
		int i1 = preparing.indexOf(flag1) + flag1.length();
		String s1 = preparing.substring(i1);
		
		// 取出未格式化的参数字符串
		int i3 = parameters.indexOf(flag2) + flag2.length();
		String s2 = parameters.substring(i3);
		
		String fullSql = fillSql(s1, s2);
		return fullSql;
	}
	
	// 用参数填充sql，形成完整sql。输入字符串已经去掉无效信息
	public String fillSql(String query, String params) {
		if(query.indexOf("?") <= 0) {
			// 查询语句不含 ?
			return query;
		}
		if(params.isEmpty()) {
			return query;
		}
		
		if(this.isDebug) {
			Console.log("fillSql输入参数： ");
			Console.log(query);
			Console.log(params);
		}
		// 分解参数字符串，得到参数类型 和 参数值
		int n = 0;
		String[] paramArr = params.split("\\),");
		if(this.isDebug) {
			Console.log("参数分割后为： ", paramArr);
		}

		List<String> types = new ArrayList<String>();
		List<String> values = new ArrayList<String>();
		
		for (String param : paramArr) {
			if(this.isDebug) {
				Console.log("{} 次 参数为： {}", n, param);
				n = n + 1;
			}
			param = param.trim();
			if(param.equals("null")) {
				types.add("Integer");
				values.add("null");
				continue; // 跳过后续，立即开始下一次
			}

			int i11 = param.lastIndexOf("("); // 最后一个左括号位置，防止参数里面自带括号

			String _v = param.substring(0, i11);
			String _t = param.substring(i11+1, param.length() ); //-1);
			
			types.add(_t);
			values.add(_v);
		}
		if(this.isDebug) {
			Console.log("\r\n源语句: ", query);
			Console.log("参数值表: ", values);
			Console.log("参数类型表: ", types);
		}
		
		for (int i = 0; i < values.size(); i++) {
			String target = values.get(i); // 用来替换的内容

			// 如果类型是String，则在前后加单引号
//			if(types.get(i).equals("String")) {
				target = "'" + target + "'";
//			}
			
			if(this.isDebug) {
				Console.log(i, ": 替换成: ", target);
			}
			// 特殊字符处理
			target = target.replace("$", "\\$");
			
			query = query.replaceFirst("\\?", target);
			if(this.isDebug) {
				Console.log("结果: ", query);
			}
		}
		if(this.isDebug) {
			Console.log("\r\n 转换结果: ", query);
		}
		
		return query;
	}
	
	@Override
	public void debug(String s) {
		boolean QUERY_SQL = true;
//		var QUERY_SQL = false;
		
		if(QUERY_SQL) {
			if (s.startsWith("==>  Preparing: ")) {
				boundSql = s;
				return;
				
			} else if( s.startsWith("==> Parameters: ")) {
				try {
					String allSql = doSql(boundSql, s);
					s = allSql;
				} catch (Exception e) {
					System.out.println("MyBatisLogImpl do sql EXCEPTION: ");
					System.out.println(e);
					
					log.debug(boundSql);
				}
				
			}
		}
		
		log.debug(s);
	}
	
	@Override
	public boolean isDebugEnabled() {
		return log.isDebugEnabled();
	}

	@Override
	public boolean isTraceEnabled() {
		return log.isTraceEnabled();
	}

	@Override
	public void error(String s, Throwable e) {
		log.error(s, e);
	}

	@Override
	public void error(String s) {
		log.error(s);
	}

	@Override
	public void trace(String s) {
		log.trace(s);
	}

	@Override
	public void warn(String s) {
		log.warn(s);
	}

}
